\documentclass[10pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{graphicx}
\usepackage{listings}  \lstset{language=SQL} \lstset{ basicstyle=\small}
\title{Abschlussbericht zum Proseminar Datenbanken Vertiefung: Geo-Terminplaner}
\author{Julia Altenried, Christoph Linecker, Robert Harsan}


\begin{document}
\begin{titlepage}
\maketitle
\end{titlepage}
\renewcommand{\contentsname}{Inhalt}
\tableofcontents

\newpage
\section{Pflichtenheft}
\subsection{Problemspezifikation}
Der GEO-Terminplaner soll Terminplanung und -vereinbarung ermöglichen. Dabei sollen neben zeitlicher Daten auch geographische Daten erfasst werden um Überschneidungen unterschiedlicher Termine zu verhindern. \\
Es gibt zwei Benutzergruppen: die Dienstleister und die Klienten, die diese Dienste in Anspruch nehmen. Der Dienstleister konfiguriert den Zeitraum, in dem Termine vereinbart werden können, bietet Aktivitäten mit definierbarer Dauer an und bietet den Kunden dazu Termine an, die von beiden Seiten abgesagt werden können. Dessen Klient kann Termine zu verfügbaren Zeiten vereinbaren.
\subsection{Anforderungen}
\begin{enumerate}
\item Selbstständiges Einrichten von Benutzern per Webinterface soll ermöglicht werden. Außerdem soll jeder Benutzer seine persönlichen Daten ändern können.
\item Authentifizierte Klienten sollen Termine vereinbaren können. Dies soll über eine Wochenansicht erfolgen, in der tabellarisch bereits belegte Termine mit Zeit und Ort sichtbar sind. Die gebuchte Aktivität und Termindauer sollen gespeichert werden.
\item Dienstleister sollen Zeiträume für die Terminplanung freigeben können, sowie die Möglichkeit haben bestimmte Tage ganz zu sperren.
\item Terminkollisionen sollen für Dienstleister vermieden werden. Dazu ist die Distanz zwischen den Terminorten zu berücksichtigen.
\item Export in einem XML-basierten Format soll für Dienstleister ermöglicht werden.
\end{enumerate}
\subsection{Realisierung}
Benutzer haben im Geoterminplaner unterschiedliche Rollen: Terminanbieter (Provider) und Terminsuchende (Clients). Je nach Zugehörigkeit stellt unsere Webapplikation unterschiedliche Perspektiven und Funktionen zur Verfügung.\newline
Klienten können im Kalenderbereich ihre Termine einsehen und dort auch innerhalb einer vom Terminanbieter festgelegten Frist auch stornieren.\newline

Das vereinbaren eines Termins ist aus der Sicht eines Klienten ein zweistufiger Vorgang: zuerst wird im Terminbereich eine der verfügbaren Leistungen ausgewählt sowie der gewünschte Ort bestimmt. Sobald die Auswahl abgeschlossen ist, können in einer Tabelle alle Anwesenheitszeiten eines Anbieters, seine Termine sowie deren Ort eingesehen werden. Schließlich muß ein Klient die von ihm gewünschte Startzeit angeben und der Termin wird angelegt, wenn:
\newpage
\begin{itemize}
\item der Termin innerhalb einer vom Anbieter festgelegten Anwesenheitszeit liegt,
\item der Termin sich nicht mit bereits gebuchten Terminen überschneidet,
\item der Anbieter diesen Termin und den nächsten Termin rechtzeitig erreichen kann (dabei wird vorausgesetzt, dass ein Anbieter einen Kilometer Luftlinie in nur fünf Minuten zurücklegen kann),
\item die Anmeldung rechtzeitig und also innerhalb der vom Anbieter bestimmten Frist liegt.
\end{itemize}
\includegraphics[scale=0.4]{screenshots/appointmentFirst.jpg}\\
\includegraphics[scale=0.4]{screenshots/appointmentSecond.jpg}\\
\includegraphics[scale=0.4]{screenshots/calendarDetail.jpg}
\newline\newline
Der Persönliche-Daten-Bereich ist für Klienten und Anbieter gleich: Name, Email, Telefonnummer, Passwort sowie Adresse können hier verändert werden.\\
\includegraphics[scale=0.4]{screenshots/personalData.jpg}
\newline\newline
Anbieter können im Geoterminplaner grundsätzlich Perspektiven wechseln und damit beide Rollen einnehmen (mit der Einschränkung, dass sie die selbst angebotenen Leistungen im Klienten-Bereich weder sehen noch buchen können). \newline

Im Anbieter-Kalender-Bereich werden ihre Anbieter-Termine angezeigt, die im Gegensatz zu Klienten-Termin jederzeit storniert werden können.  Darüber hinaus können die im Kalender angezeigten Termine in das xCal-Format umgesetzt und heruntergeladen werden (dabei werden die, einen Termin repäsentierenden, vEvents aus der Datenbank gelesen und zu einem iCalendar gebündelt).\\
\includegraphics[scale=0.4]{screenshots/providerSchedule.jpg}
\newline\newline
Im Anwesenheitszeit-Bereich können Provider An- und Abwesenheitszeiten speichern und verändern. Dabei gilt:
\begin{itemize}
\item Anwesenheitszeiten dürfen sich nicht überschneiden,
\item bereits gespeicherte Anwesenheitszeiten können nur dann geändert werden, wenn nach der Änderung kein gebuchter Termin außerhalb einer Anwesenheitszeit liegt,
\item eine Abwesenheitszeit darf nur dann gespeichert werden, wenn sie sich nicht mit einem bereits gebuchten Termin liegt,
\item die Startzeit muss in der Zukunft liegen (und der Start muss vor dem Ende liegen),
\item bei der Berechnung der tatsächlichen Anwesenheitszeiten Abwesenheitszeiten Anwesenheitszeiten schlagen (tatsächliche Anwesenheitszeit = Anwesenheitszeiten – Abwesenheitszeiten).
\end{itemize}
\includegraphics[scale=0.4]{screenshots/availabilityDialog}\newline
\includegraphics[scale=0.4]{screenshots/availabilityOverview}
\newline
In der Leistungsansicht verwalten Anbieter die von ihnen zur Verfügung gestellten Dienstleistungen. Anders als bei Anwesenheitszeiten können Leistungen nicht verändert, sondern ausschließlich erstellt und, sofern noch kein Termin für eine Leistung gebucht worden ist, auch wieder gelöscht werden. Leistungen haben im Geoterminplaner eine Gültigkeitsdauer, werden also nur innerhalb eines bestimmten Zeitfensters angeboten, laufen schließlich ab und können somit nicht mehr angezeigt und gebucht werden. Die Gültigkeitsbereiche von Leistungen mit gleichen Namen dürfen sich nicht überschneiden.\\
\includegraphics[scale=0.4]{screenshots/serviceOverview}
\section{ER-Diagramm}

\includegraphics[scale=0.5]{er-folie.pdf}

\section{Diskussion wesentlicher Designentscheidungen}

\subsection{Präsentationsschicht}

\subsubsection{Überblick über JSF}
$JavaServerFaces$ ist die aktuelle Standardtechnologie für die UI Schicht im Java
EE Standard\footnote[1]{http://www.oracle.com/technetwork/java/javaee/overview-140548.html}. Da Tomcat keine JSF Implementierung inkludiert nutzen wir die JSF
Referenzimplementierung Mojarra\footnote[2]{http://javaserverfaces.java.net/}.\\
Ähnlich wie die immer noch unterstützte JSP Technologie werden Antworten auf
Requests zum Server aus einer Template-Datei erzeugt. Bei JSF sind diese im
.xhtml Format.Verglichen mit JSP erzwingt JSF eine striktere Trennung von
Präsentation und Logik.\\
So gibt es keine direkte Einbettung von Java Code in die Template-Datei und es
können nur noch Methoden mit bestimmten Signaturen vor dem Rendern von
Komponenten oder beim Verarbeiten eines POST Requests ausgeführt werden.
Weiter können Variablen nicht außerhalb von Backing Beans (siehe Dependency
Injection ) global für eine .xhtml Datei definiert werden. Unsere .xhml Dateien
befinden sich in termine\textbackslash src\textbackslash main\textbackslash webapp\textbackslash faces.\\
JSF bietet eigene Tags an, die UIComponent\footnote[3]{http://docs.oracle.com/javaee/6/api/javax/faces/component/UIComponent.html} Klassen entsprechen und erst beim
Verarbeiten eines Requests in für den Client verständlichem Code umgewandelt
werden. Das hat mehrere Vorteile:\\
Erstens werden Properties der Backing Beans automatisch gesetzt, ohne das man
manuell den Request parsen muss. So würde \\ $\left\langle h:inputText \: value=”bean.property” / \right\rangle$ einen HTML $input$ Tag generieren und die Variable
$property$ aus der Bean namens $bean$ lesen und und beim Submitten der $form$ auf
den eingegebenen wert setzen, bevor die durch das Submitten der Form
gewünschte Methode (die auch ohne manuelles Parsen gefunden ist) ausgeführt
wird.\\
Zweitens wird die Last, mit allen weit-verbreiteten Browsern kompatiblen Code zu
erzeugen, auf die JSF Implementierung ausgelagert, auch für Komplexere HTML-Controlls
oder AJAX.\\
Drittens kann das erzeugen bestimmter Konstrukte im Vergleich zu normalen
XHTML deutlich vereinfacht werden, so kann zB ein $h:panelGrid$ Tag eine HTML Tabelle erzeugen und nach einer bestimmten Anzahl von Elementen eine neue
Zeile beginnen, ohne das $tr$ oder $td$ Tags geschrieben werden müssen.\\
Weiter können Datentabellen oder Selektoren leicht Datenstrukturen aus einer
Backing Bean übergeben werden, über die automatisch iteriert wird und für jedes
Element der Struktur ein Eintrag ausgegeben wird.\\
Sind Tags für die gewünschte Funktionalität nicht vorhanden, kann man auf
normale XHTML Tags zurück greifen, eigene Tags implementieren, oder eine der
zahlreichen frei verfügbaren Libraries setzen.

\subsubsection{PrimeFaces}
Da in den standard JSF Tags keine Kalenderkomponente vorhanden ist, nutzen wir
die Library $PrimeFaces$. Diese erlaubt es einfach einen funktionalen und optisch
ansprechenden Kalender zu erzeugen.\\
Dazu wandeln wir unsere Appointments in
$org.primefaces.model.ScheduleEvents$ um und stellen diese über ein $ScheduleModel$ dem $p:schedule$ Tag wie folgt zur verfügung:\newline
$\langle p:schedule value="\#\{providerScheduleJSF.providerScheduleModel\}"$ ...\newline
\newline
PrimeFaces bietet für so gut wie alle JSF Tags eigene Varianten an, die oft
zusätzliche Optionen oder einfachere Konfiguration bieten als die standard-Tags.
Diese Tags erzeugen weiters aufwendig stilisierte HTML Tags im Gegensatz zu den
CSS-freien JSF Tags, weshalb wir überall auf diese Versionen zugreifen.


\subsection{Datenbankverbindung}
Für die Datenbankverbindung nutzen wir eine\\
$org.apache.tomcat.jdbc.pool.DataSource$, die das Wiederverwenden von
Connections erlaubt. Ruft man $connection.close()$ auf, so wird die Connection falls
möglich nicht entfernt sondern in einem Pool gelegt und beim Aufruf von $getConnection()$
wiederverwendet. Da wir in jedem Aufruf einer Manager-Methode $getConnection($) aufrufen,
sollte so viel weniger oft eine neue Verbindung aufgebaut werden müssen.\\
Die $DataSource$ stellen wir zudem so ein, dass Connections mit $autoCommit$ auf $false$
zurückgegeben werden und Connections, die seit länger als 120 Sekunden offen sind,
automatisch geschlossen werden $(RemoveAbandoned)$.\\
Ursprünglich wollten wir die Datenbankverbindung mit einer $javax.sql.DataSource$ in der
$context.xm$l unserer Webapp herstellen. In diesem Fall überlässt man das Erzeugen der
DataSource dem Application Server. Tomcat baut hier dann eine gepoolte DataSource ohne
das wir dies explizit angeben oder weitere Abhängigkeiten haben.\\
Das Connection Pooling in Tomcat 6 wird mit $commons-dbcp$ implementiert. Die hier
ausgelieferte Version (auch mit der aktuellen Version von Tomcat 6) scheint aber soweit wir
feststellen können Fehler zu haben, die zu \\ $AbstractMethodErrors$ führen, wenn
bestimmte Methoden in den aus der von Tomcat erstellten Connection und ResultSet
Objekten aufgerufen werden.\footnote[4]{http://bugs.mysql.com/bug.php?id=48035}\\
Deshalb nutzen wir die $tomcat-jdbc$\footnote[5]{http://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html} Bibliothek aus Tomcat 7, die ähnliche
Konfiguriationsmöglichkeiten hat und zudem performanter ist.

\subsection{Redis}
Ist die Einstellung $use\_redis$ in der Datei $\setminus WEB-INF \setminus classes\setminus termine.properties$ auf $true$, so werden die Daten
des eingeloggten Benutzers ($PersonalData$ und $Location$) statt in der Servlett-Session in einer $Redis$ Datenbank
gespeichert.
Aufgrund der extermem Unerreichbarkeit der $Redis$ Datenbank auf $vampir$ ist dieser Modus jedoch $ungetestet$ und deshalb standardmäßig ausgeschalten und wird nur $experimentell$ angeboten.

\subsection{Dependency Injection}
\subsubsection{Beans}
Eine Java Bean ist ein Objekt einer Klasse, die einen leeren Konstruktor hat und
die Variablen über Getter -und Settermethoden zugänglich macht (Properties).
Weiters müssen diese Methoden für die variable $variablename$ wie folgt heißen:
$getVariablename / setVariablename / isVariablename$(für booleans).\\
Befindet sich eine Beans zudem in einer durch die Expression Language
zugängliche Map, das heißt man kann auf die Bean namens bean mit $\#\{bean\}$ aus
einer .jsp oder .xhtml Seite zugreifen, so bezeichnen wir sie als eine Backing
Bean.
\subsubsection{Scopes}
Die $Servlet-API$ bietet drei Maps von $String$ auf $Objekt$ an, die unterschiedliche Lebensspannen haben, an.
Aus einem $javax.servlet.http.HttpServletRequest$ kann man mit der
Methode $getAttribute(String)$ auf Objekte einer Map zugreifen, die für die Dauer
des aktuellen Request existiert. Solche Beans nennt man $Request Scoped$.\\
Zusätzlich bekommt man durch die $getSession()$ Methode zugriff auf Beans, die
für die Dauer der aktuellen Browser-Session existieren. Diese Beans sind also $Session
Scoped$.\\
Neben der Session gibt es auch den $javax.Servlet.ServletContext$, von dem ein Objekt pro Webapplikation im Servlet-Container gibt.
Die Attribute hier existieren also so lange, wie die Applikation und heißen dementsprechend\\
$Application Scoped$.JSF erlaubt das setzen des Scopes der Objekte einer Klasse mit der
$@ManagedBean$ Annotation. Deklariert man eine Klasse wie folgt: \\
$@ManagedBean$\\
$@ApplicationScoped$\\
$public \: class \: AppointmentManager$\\
so wird ein Objekt der Klasse AppointmentManager unter dem Key \\
$appointmentManager$ als Attribut des ServletContexts der Anwendung gesetzt.
Wir übergeben den Methoden unserer Logik-und Datenbankzugriffsschicht immer die notwendigen
Parameter aus der Präsentationsschicht und haben in diesen Klassen keinen lokalen Zustand, wodurch diese threadsafe sind.
Deshalb sind alle unsere DAO und Manager Klassen Application Scoped.\\
JSF beitet zusätzlich den $ViewScope$ an, bei dem die Beans so lange erhalten bleiben wie
die Requests innerhalb einer Session auf die gleiche View (.xhtml Datei)
zugreifen. Dies hat den Vorteil, das die Variablen in einem Objekt zwischen
Requests erhalten bleiben, was vor allem dann nützlich ist, wenn man Daten aus
der Datenbank ausliest. Im Request Scope müsste man die Daten bei jedem
Request neu laden da die Bean nach der Antwort des Servers nicht mehr exisitert.\\
Das einmal gesetzte Properties erhalten bleiben vereinfacht viele Aspekte der
Programmierung der Präsentationsschicht, die durch die zustandslose Natur von
HTTP erschwert werden können. Deshalb ist unsere Präsentationsschicht im View Scope.\\
Eine Ausnahme ist die $LoginJSF$, die den aktuellen Benutzer der Anwendung im Session
Scope speichert.
\subsubsection{Injection}
Annotiert man eine Property einer Managed Bean mit @ManagedProperty, werden diese
Properties von JSF jedes Mal, dass ein Object dieser Klasse konstruiert wird, gesetzt. Ein
Beispiel aus $LoginJSF$:\\
$@ManagedProperty(value = "\#\{personalDataManager\}")$\\
$private PersonalDataManager personalDataManager;$\\
In diesem Fall wird jedes Mal, dass ein LoginJSF Objekt erzeugt wird eine Referenz auf den
personalDataManager gesetzt, der im Application Scope ist.
Eine ManagedProperty muss den gleichen oder einen längerlebigenren Scope haben als
ManagedBean, in die sie injected wird.
\section{Anhang}
\subsection{Tabellen}
\begin{lstlisting}
--==============================================================
-- Table: APPOINTMENT
--==============================================================
create table APPOINTMENT
(
   AP_ID                INTEGER                not null 
   	generated always as identity (start with 1, increment by 1, no cache),
   L_ID                 INTEGER                not null,
   S_ID                 INTEGER                not null,
   C_ID                 INTEGER                not null,
   AP_START             TIMESTAMP              not null,
   AP_CALENDAR          XML                    not null,
   constraint P_AP_ID primary key (AP_ID)
);

--==============================================================
-- Index: HAS_FK
--==============================================================
create index HAS_FK on APPOINTMENT (
   S_ID                 ASC
);

--==============================================================
-- Index: BOOKS_FK
--==============================================================
create index BOOKS_FK on APPOINTMENT (
   C_ID                 ASC
);

--==============================================================
-- Index: TAKES_PLACE_FK
--==============================================================
create index TAKES_PLACE_FK on APPOINTMENT (
   L_ID                 ASC
);

--==============================================================
-- Table: AVAILABILITY
--==============================================================
create table AVAILABILITY
(
   AV_ID                INTEGER                not null 
   	generated always as identity (start with 1, increment by 1, no cache),
   P_ID                 INTEGER                not null,
   AV_START             TIMESTAMP              not null,
   AV_END               TIMESTAMP              not null,
   AV_TYPE              VARCHAR(15)            not null,
   constraint P_AV_ID primary key (AV_ID)
);

--==============================================================
-- Index: IS_AVAILABLE_FK
--==============================================================
create index IS_AVAILABLE_FK on AVAILABILITY (
   P_ID                 ASC
);

--==============================================================
-- Table: CLIENT
--==============================================================
create table CLIENT
(
   C_ID                 INTEGER                not null 
   	generated always as identity (start with 1, increment by 1, no cache),
   PD_ID                INTEGER                not null,
   constraint P_C_ID primary key (C_ID)
);

--==============================================================
-- Index: CLIENT_DEF_BY2_FK
--==============================================================
create index CLIENT_DEF_BY2_FK on CLIENT (
   PD_ID                ASC
);

--==============================================================
-- Table: LOCATION
--==============================================================
create table LOCATION
(
   L_ID                 INTEGER                not null 
   	generated always as identity (start with 1, increment by 1, no cache),
   L_COUNTRY            VARCHAR(50)            not null,
   L_CITY               VARCHAR(50)            not null,
   L_ZIP                VARCHAR(10)            not null,
   L_STREET             VARCHAR(100)           not null,
   L_POSITION           db2gse.ST_Point        not null,
   constraint P_L_ID primary key (L_ID)
);

--==============================================================
-- Table: PERSONAL_DATA
--==============================================================
create table PERSONAL_DATA
(
   PD_ID                INTEGER                not null 
   	generated always as identity (start with 1, increment by 1, no cache),
   L_ID                 INTEGER                not null,
   C_ID                 INTEGER,
   P_ID                 INTEGER,
   PD_FORENAME          VARCHAR(25)            not null,
   PD_SURNAME           VARCHAR(25)            not null,
   PD_PHONE_NUMBER      VARCHAR(25),
   PD_EMAIL             VARCHAR(50)            not null,
   PD_PASSWORD          VARCHAR(50)            not null,
   constraint P_PD_ID primary key (PD_ID)
);

alter table PERSONAL_DATA add unique (PD_EMAIL);

--==============================================================
-- Index: LIVES_FK
--==============================================================
create index LIVES_FK on PERSONAL_DATA (
   L_ID                 ASC
);

--==============================================================
-- Index: PROV_DEF_BY2_FK
--==============================================================
create index PROV_DEF_BY2_FK on PERSONAL_DATA (
   P_ID                 ASC
);

--==============================================================
-- Index: CLIENT_DEF_BY_FK
--==============================================================
create index CLIENT_DEF_BY_FK on PERSONAL_DATA (
   C_ID                 ASC
);

--==============================================================
-- Table: PROVIDER
--==============================================================
create table PROVIDER
(
   P_ID                 INTEGER                not null 
   	generated always as identity (start with 1, increment by 1, no cache),
   PD_ID                INTEGER                not null,
   constraint P_P_ID primary key (P_ID)
);

--==============================================================
-- Index: PROV_DEF_BY_FK
--==============================================================
create index PROV_DEF_BY_FK on PROVIDER (
   PD_ID                ASC
);

--==============================================================
-- Table: SERVICE
--==============================================================
create table SERVICE
(
   S_ID                 INTEGER                not null 
   	generated always as identity (start with 1, increment by 1, no cache),
   P_ID                 INTEGER                not null,
   S_NAME               VARCHAR(50)            not null,
   S_DESCRIPTION        VARCHAR(500),
   S_DURATION_IN_MIN    INTEGER                not null,
   S_BOOK_DEADLINE_IN_MIN   INTEGER            not null,
   S_CANCEL_DEADLINE_IN_MIN INTEGER            not null,
   S_START              TIMESTAMP              not null,
   S_END                TIMESTAMP              not null,
   constraint P_S_ID primary key (S_ID)
);

--==============================================================
-- Index: PROVIDES_FK
--==============================================================
create index PROVIDES_FK on SERVICE (
   P_ID                 ASC
);

alter table APPOINTMENT
   add constraint F_BOOKS foreign key (C_ID)
      references CLIENT (C_ID)
      on delete restrict on update restrict;

alter table APPOINTMENT
   add constraint F_HAS foreign key (S_ID)
      references SERVICE (S_ID)
      on delete restrict on update restrict;

alter table APPOINTMENT
   add constraint F_TAKES_PLACE foreign key (L_ID)
      references LOCATION (L_ID)
      on delete restrict on update restrict;

alter table AVAILABILITY
   add constraint F_IS_AVAILABLE foreign key (P_ID)
      references PROVIDER (P_ID)
      on delete restrict on update restrict;

alter table CLIENT
   add constraint F_CLIENT_DEF_BY2 foreign key (PD_ID)
      references PERSONAL_DATA (PD_ID)
      on delete restrict on update restrict;

alter table PERSONAL_DATA
   add constraint F_CLIENT_DEF_BY foreign key (C_ID)
      references CLIENT (C_ID)
      on delete restrict on update restrict;

alter table PERSONAL_DATA
   add constraint F_LIVES foreign key (L_ID)
      references LOCATION (L_ID)
      on delete restrict on update restrict;

alter table PERSONAL_DATA
   add constraint F_PROV_DEF_BY2 foreign key (P_ID)
      references PROVIDER (P_ID)
      on delete restrict on update restrict;

alter table PROVIDER
   add constraint F_PROV_DEF_BY foreign key (PD_ID)
      references PERSONAL_DATA (PD_ID)
      on delete restrict on update restrict;

alter table SERVICE
   add constraint F_PROVIDES foreign key (P_ID)
      references PROVIDER (P_ID)
      on delete restrict on update restrict;


\end{lstlisting}

\subsection{Trigger}
\begin{lstlisting}
DROP TRIGGER ON_USER_LOCATION_CHANGE;
DROP TRIGGER ON_APPOINTMENT_DELETE;

CREATE TRIGGER ON_USER_LOCATION_CHANGE
AFTER UPDATE OF L_ID ON PERSONAL_DATA
FOR EACH ROW
MODE DB2SQL
delete FROM location
WHERE L_ID NOT IN (SELECT L_ID FROM personal_data) 
and L_ID NOT IN (SELECT L_ID FROM appointment);

CREATE TRIGGER ON_APPOINTMENT_DELETE
AFTER DELETE ON APPOINTMENT
FOR EACH ROW
MODE DB2SQL
delete FROM location
WHERE L_ID NOT IN (SELECT L_ID FROM personal_data) 
and L_ID NOT IN (SELECT L_ID FROM appointment);
\end{lstlisting}
\newpage
\subsection{Dokumentation}

\subsubsection{Überblick über die Architektur}
 
Unsere wichtigsten Klassen sind in die folgenden Pakete aufgeteilt:
\begin{itemize}
\item $org.termine.jsf$: Präsentationsschicht. Auf Beans dieser Klassen greifen die .xhtml Seiten
zu.
\item $org.termine.logic$: Muss auf die Datenbank zugegriffen werden, rufen die JSF Klassen
eine Manager Klasse auf. Diese Klassen beinhalten die meiste Logik, rufen DAO Klassen
für Datenbank-Operationen auf und handhaben die Transaktionen, die an die DAOs
übergeben werden.
\item $org.termine.dao$: Diese Klassen führen SQL Statements aus und verpacken die Resultate
in Objekte, mit denen wir weiterarbeiten.
\item $org.termine.entity$: Diese Klassen repräsentieren zum einen Teil unsere Datenbankentitäten, aber auch Klassen für einzelne Primfaces Widgets.
\item $org.termine.db$: Die Connector-Klasse stellt Connection Objekte zur Verfügung. Außerdem stellt sie Methoden für commit, rollback und schließen einer Connection bereit.
\item $org.termine.util$: Klassen für das Zusammensetzen von Xml-Dateien und die GeoCoder-Klasse nutzt die die Google-Maps-API und gibt für eine übergebene Adresse Längen- und Breitengrade zurück.

\end{itemize}

\subsubsection{Ausführen von SQL Statements und Transaktionsmanagement}

Beim Zugriff auf die Datenbank haben wir folgenden Ablauf:
\begin{itemize}
\item Falls nötig validiert der Manager die Eingaben und führt sonstige Logik aus.
\item Try Block wird angefangen
\item Manager holt sich eine Connection und ruft eine oder Mehrere Methoden aus DAO
Klassen auf. Die Connection hat autoCommit auf false. Näheres dazu in
Datenbankverbindung.
\item Die DAO Klasse erzeugt einen PreparedStatement und setzt die vom Manager
übergebenen Parameter. Durch die parametrisierten PereparedStatements werden
SQL-Injections verhindert.
\item Die DAO führt das Statement aus und packt die Resultate der Abfrage in Objekte für die
Entitäten, die an den Manager zurückgegeben werden, falls die abfrage lesend war.
\item Falls die Methode schreibt, wird der DAO eine Entität übergeben, dessen Properties in
einem PereparedStatement gesetzt werden.
\item Manager Methode macht weiter, bis mit try Block fertig oder Exception Aufgetreten ist.
\item Waren die DAO Methoden alle nur lesend, wird in einem finally Block die
Connection geschlossen
\item Sonst wird commited, oder ein Rollback ausgeführt, falls ein Fehler aufgetreten ist.
\end{itemize}


\end{document}